home *** CD-ROM | disk | FTP | other *** search
- /*
- HASUtilDialogs.c from Hsoi's App Shell. © 1995-1997 John C. Daub. All rights reserved.
-
- This file contains various dialog utility functions (stuff that's pretty easy to
- reuse as-is in your own code and in various places throughout the shell).
-
- */
-
- #pragma mark ••• #includes •••
-
- #ifndef _WASTE_
- #include "WASTE.h"
- #endif
- #include "HASGlobals.h"
- #ifndef __HSOIS_APP_SHELL__
- #include "HASMain.h"
- #endif
- #include "HASUtilDialogs.h"
- #include "HASDialogs.h"
- #include "HASMiscEvents.h"
- #include "HASUtilities.h"
- #ifndef _STDIO
- #include <stdio.h>
- #endif
- #ifndef _STRING
- #include <string.h>
- #endif
-
- #pragma mark -
- #pragma mark ••• Std Filter •••
-
- // this is our standard, generic dialog filter, used throughout the code (more or less)
- // when we need a dialog filter. you can easily reuse it too, but make sure to
- // modify it to fit your needs, and also, make sure that you can use this filter in your
- // situation (like we cannot use this for Get/PutFile dialogs.
-
-
- pascal Boolean hsoiMyStandardDialogFilter( DialogRef dialog, EventRecord *event, short *item )
- {
- GrafPtr savePort;
- ModalFilterUPP stdFilter = nil;
- Boolean reply = false;
- OSErr err;
- Boolean handled = false;
-
- // set up the port
-
- GetPort( &savePort );
- SetGrafPortOfDialog( dialog );
-
- // intercept window events directed to widnows behind the dialog
-
- if ( ( event->what == updateEvt ) || ( event->what == activateEvt ) )
- {
- if ( (DialogRef)(event->message) != dialog )
- {
- if ( event->what == updateEvt )
- HsoiDoUpdate( (WindowRef)(event->message) );
- else if ( event->what == activateEvt )
- HsoiDoActivate( (event->modifiers & activeFlag != 0), (WindowRef)(event->message) );
-
- } // end if (WindowPtr)whatEvent != dialog
-
- }
-
- // is the default item a pushbutton?
-
- if ( HsoiGetDialogItemType( dialog, GetDialogDefaultItem(dialog) ) == kButtonDialogItem )
- {
- // yes, so tell the Dialog Manager to care about its outline
-
- err = SetDialogDefaultItem( dialog, GetDialogDefaultItem(dialog));
- if ( err != noErr )
- HsoiDoError( rWindowErrorStrings, strStdDlgFilterSetDef, err, kErrGeneric );
- }
-
- // let's also make sure the cancel button can be handled...now, the cancel button
- // should be dialog item #2. So, we get dialog item #2, check if it's a button.
- // if it fills these 2 criteria, it's cancel. Even if the default item and the
- // cancel item are the same, still let them both be set this way so whatever keyboard
- // keys sthe user presses will be handled properly
-
- // remember, this assumes that your cancel item will be item #2 (or at least the item
- // that you want to use for cancelling is #2), and that there are at least 2 items in
- // the dialog to begin with!
-
- if ( HsoiGetDialogItemType( dialog, kStdCancelItemIndex ) == kButtonDialogItem )
- {
- err = SetDialogCancelItem( dialog, kStdCancelItemIndex );
- if ( err != noErr )
- ; // put error handling in here
- }
-
-
- // call the standard Dialog Manager filter procedure
-
-
- err = GetStdFilterProc( &stdFilter );
- if ( (err == noErr) && (!handled) )
- reply = CallModalFilterProc( stdFilter, dialog, event, item );
-
- // restore the port
- SetPort( savePort );
-
- return reply;
- }
-
- /*
- * Use this routine to obtain a Universal ProcPtr to the generic dialog filter
- * (the routine above). Since it's a global variable, it makes sure it doesn't
- * already exist (to save some time with mixed mode stuff)
- */
-
- pascal ModalFilterUPP HsoiGetMyStandardDialogFilter( void )
- {
- if ( gMyStdDlogFilterProc == nil )
- gMyStdDlogFilterProc = NewModalFilterProc(hsoiMyStandardDialogFilter);
-
- return gMyStdDlogFilterProc;
- }
-
- #pragma mark -
- #pragma mark ••• Dlg Item Accessors •••
-
- /*
- * A nice quick routine that gets and returns the itemType of a dialog item
- */
-
-
- short HsoiGetDialogItemType( DialogRef dialog, short item )
- {
- short itemType;
- Handle itemHandle;
- Rect itemRect;
-
- GetDialogItem( dialog, item, &itemType, &itemHandle, &itemRect );
-
- return itemType;
- }
-
- /*
- * A nice quick routine that returns the Handle to a dialog item
- */
-
-
- Handle HsoiGetDialogItemHandle( DialogRef dialog, short item )
- {
- short itemType;
- Handle itemHandle;
- Rect itemRect;
-
- GetDialogItem( dialog, item, &itemType, &itemHandle, &itemRect );
-
- return itemHandle;
- }
-
- /*
- * A nice quick routine that returns the Rect of a dialog item
- */
-
- void HsoiGetDialogItemRect( DialogRef dialog, short item, Rect *itemRect )
- {
- short itemType;
- Handle itemHandle;
-
- GetDialogItem( dialog, item, &itemType, &itemHandle, itemRect );
-
- return;
- }
-
-
- /*
- * A nice quick routine that can set a procedure for a dialog item
- */
-
- pascal void HsoiSetDialogItemProc( DialogRef dialog, short item, UserItemUPP proc )
- {
- short itemType;
- Handle itemHandle;
- Rect itemRect;
-
- GetDialogItem( dialog, item, &itemType, &itemHandle, &itemRect );
-
- if ( (itemType & 0x007F) == kUserDialogItem )
- SetDialogItem( dialog, item, itemType, (Handle)proc, &itemRect );
-
- return;
- }
-
- // this will set a dialog item's state to whatever value you pass it (good for
- // setting the state of checkboxes, radio buttons, etc)
-
- void HsoiSetDialogItemState( DialogRef dlg, short controlNumber, short value )
- {
- Handle iHandle;
-
- iHandle = HsoiGetDialogItemHandle( dlg, controlNumber );
- SetControlValue( (ControlRef)iHandle, value );
-
- return;
- }
-
- // tho this routine is really only useful in the big modal dialog sample, it can
- // give you can idea of a way to handle radio buttons.
-
-
- void HsoiSetRadioButton( DialogRef dlg, short buttonNumber )
- {
- if ( buttonNumber != gCurrentRadio )
- {
- if ( gCurrentRadio != 0 )
- HsoiSetDialogItemState( dlg, gCurrentRadio, 0 );
-
- gCurrentRadio = buttonNumber;
-
- if ( ( gCurrentRadio >= kRadioButtonFirst ) && ( gCurrentRadio <= kRadioButtonLast ) )
- HsoiSetDialogItemState( dlg, gCurrentRadio, 1 );
- }
-
- return;
- }
-
- // BorderDefault draws a heavy border around the default button (in this case the OK button )
- // Again, not necessary if the new DM calls are in (i.e. not necessary for Hsoi's App Shell,
- // but I'm leaving it in the code just in case you're someone that might be interested
- // in knowing how to do this sort of thing)
-
- pascal void HsoiBorderDefault(WindowRef dwind, short dinum)
- {
- #pragma unused (dinum)
-
- Rect borderRect;
-
- HsoiGetDialogItemRect( dwind, ok, &borderRect );
-
- // ok is defined as 1 in the interfaces. If you'd like another item outlined,
- // change this number, of course.
-
- InsetRect(&borderRect, -4, -4);
- PenSize(3, 3);
- FrameRoundRect(&borderRect, 16, 16);
- PenSize(1, 1);
-
- return;
- } // end BorderDefault
-
-
-
- // a little utility to see if the current key is an edit-type key
-
- Boolean HsoiIsEditKey(char theKey, short modifiers)
- {
- register qq;
- Boolean returnVal = false;
- char editChars[] =
- {
- kLeftArrow, kUpArrow, kRightArrow, kDownArrow, kBackSpace, kEscKey
- };
- char commandEdits[] =
- {
- 'C', 'V', 'X' // for some reason, in the original DialogBits, C.K. Haun
- // had C, V and P in here...go figure?
- };
-
- for (qq = 0; qq < sizeof(editChars) / sizeof(char); qq++)
- {
- if (theKey == editChars[qq])
- returnVal = true;
- }
- if (returnVal != true && (modifiers & cmdKey))
- {
- // check for XCP
- // Do you want me to use toupper? What! And link in all of StdLib! aggggg
-
- if (theKey >= 0x61 && theKey <= 0x7a)
- theKey -= 0x20;
- for (qq = 0; qq < sizeof(commandEdits) / sizeof(char); qq++)
- {
- if (theKey == commandEdits[qq])
- returnVal = true;
- }
- }
- return(returnVal);
- } // end IsEditKey
-
-
- // Gets the ControlHandle for the item you want in the dialog box thebox.
- // Handy for setting checkboxes and radio buttons
- // This is the _most_ copied routine from this file
-
- ControlRef HsoiSnatchHandle(DialogRef thebox, short theGetItem)
- {
- Handle thandle;
-
- thandle = HsoiGetDialogItemHandle( thebox, theGetItem );
- return((ControlRef)thandle);
-
- } // end SnatchHandle
-
-
- //COPLAND - this entire function breaks under STRICT macros cause of how it
- //takes a DialogPeek as an argument, and how it accesses elements of a DialogRecord,
- // all things which will no longer exist under Copland
- short HsoiHasSelectionRange(DialogPeek inputDialog)
- {
- TEHandle theTERecord = inputDialog->textH;
- short returnVal = (*theTERecord)->selEnd -(*theTERecord)->selStart;
-
- return(returnVal);
- } // end HasSelectionRange
-
-
-
- // this function draws a nice little "frame" around dialog items. for items in
- // dialogs that you'd like grouped together (e.g. a group of related radio buttons)
- // you can create a user item in the DITL to group these together. then, install
- // this function as a user item proc (UserItemUPP) for that user item and it'll
- // draw a nice little frame around them.
-
- pascal void HsoiDrawGroupBox( WindowRef dialog, short item )
- {
- GrafPtr savePort;
- Rect r;
-
- // get and save the old port
-
- GetPort( &savePort );
-
- // set the port to our dialog
-
- SetPort( dialog );
-
- // get the rect for the user item
-
- HsoiGetDialogItemRect( dialog, item, &r );
-
- // frame it up
-
- FrameRect( &r );
-
- // and restore the old port
-
- SetPort( savePort );
-
- return;
- }
-
- // this is very similar in function to HsoiSetDialogItemState, except we take a Boolean
- // instead of a short. It can just allow for more readable code.
-
- void HsoiDlgSetCheck( DialogRef dlg, short item, Boolean value )
- {
- Handle itemHandle;
-
- itemHandle = HsoiGetDialogItemHandle( dlg, item );
- SetControlValue((ControlRef)itemHandle,value);
-
- // since this is so similar to HsoiSetDialogItemState, if we just wanted to have
- // HsoiDlgSetCheck exist purely to create more readable code, we could change
- // this function to be only one line:
-
- // HsoiSetDialogItemState( dlg, item, (short)value );
- }
-
- // this will return the state of a checkbox: return true for on, false for off.
-
- Boolean HsoiDlgGetCheck (DialogRef dlg, short item)
- {
- Handle itemHandle;
-
- itemHandle = HsoiGetDialogItemHandle( dlg, item );
- return (GetControlValue((ControlRef)itemHandle) == 1);
- }
-
- // whatever the current setting of a checkbox, this will flip it to the other
-
- void HsoiDlgToggleCheck(DialogRef dlg, short item)
- {
- Handle itemHandle;
- short value;
-
- itemHandle = HsoiGetDialogItemHandle( dlg, item );
- value = (GetControlValue((ControlRef)itemHandle) == 1) ? 0 : 1;
- SetControlValue((ControlRef)itemHandle,value);
-
- return;
- }
-
- Boolean HsoiDlgGetRadio( DialogRef dlg, short item )
- {
- // same thing as HsoiDlgGetCheck() in concept, so we'll just call that function
- // but this gives it a more readable name for the usage
-
- return ( HsoiDlgGetCheck( dlg, item ) );
- }
-
- // yet another function that will return a ControlRef of a dialog item.
- // HsoiSnatchHandle and typecasting the return of HsoiGetDialogItemHandle
- // (i.e. (ControlRef)HsoiGetDialogItemHandle()) will all do the same thing.
-
- ControlRef HsoiDlgGetControl (DialogRef dlg, short item)
- {
- Handle itemHandle;
-
- itemHandle = HsoiGetDialogItemHandle( dlg, item );
- return (ControlRef)itemHandle;
- }
-
- // this will set the text of a dialog item to a value that you pass it
-
- void HsoiDlgSetNumber (DialogRef dlg, short item, short value)
- {
- Handle itemHandle;
- Str255 valStr;
-
- NumToString(value, valStr);
- itemHandle = HsoiGetDialogItemHandle( dlg, item );
- SetDialogItemText(itemHandle, valStr);
-
- return;
- }
-
-
- // this will get the text of a dialog item (returned in "value" as a Pascal string)
-
- void HsoiDlgGetPString( DialogRef dlg, short item, StringPtr value )
- {
- Handle itemHandle;
-
- itemHandle = HsoiGetDialogItemHandle( dlg, item );
- GetDialogItemText( itemHandle, value );
-
- return;
- }
-
- // and this will set a dialog item's text to a given Pascal string
-
- void HsoiDlgSetPString( DialogRef dlg, short item, StringPtr value )
- {
- Handle itemHandle;
-
- itemHandle = HsoiGetDialogItemHandle( dlg, item );
- SetDialogItemText( itemHandle, value );
-
- return;
- }
-
-
-
-
- /*
- This function, HsoiGetDoubleItem(), was given to me by Scott Pogorelc. It's a nice
- little way to get a floating point value from a dialog item. Since all numbers in
- dialogs are really in Str255's, we need a nice way to convert the number as a string
- to a number as a number. For whole numbers, we usually do this same thing, but
- then just call StringToNum() to convert it.
-
- Unfortuately, StringToNum (and NumToString) only work on whole numbers. For
- real numbers (i.e. w/ decimals), we can't do this. There is a nice toolbox
- routine called StringToExtended that takes care of floating point numbers.
- (they used to be called, FormatX2Str() and FormatStr2X() and if you're looking
- these routines up in THINK Ref (>= 2.0.1), they're under these names)
-
- The nice thing about this is that 1. is does what we need, 2. it doesn't require
- ANSI C library functions and hence the need to link in the ANSI libs.
-
- And there is another bonus to using StringToExtended...it's localizable. Not
- everywhere in the world do they use a comma as the thousands seperator and
- a period as the decimal seperator (as we do in the USA, e.g. 1,234,567.890).
- StringToExtended can take these things into account and make sure that your
- number manipulations all work right.
-
- However, this is also a reason why I am not using StringToExtended.
-
- Due to the fact that you have to do all this junk to deal with the international
- ways of being, there's a lot of "overhead" IMHO. It's really not all that
- hard, but it's just stuff I don't want to deal with (i'm being lazy). Plus,
- how much need for this is there? Since these functions (within the scope of HAS)
- are just being used for the print options dialog to get the margins setting,
- and the fact that the margins are in inches, I don't think we it's all THAT
- necessary to worry about localization (where else in the world do they use
- inches but the USA? anyone using inches as their measurement ought to know
- to use a period as the decimal seperator. besides, as it stands now, HAS
- is localized for the USA anyways). (some of this reasoning came out of a
- discussion I had with Tom Bender, the author of the code this is all based upon.
- if this reasoning is wrong, please let me know so I can pass the world along
- to Tom also).
-
- So, even tho the standard ANSI C library functions don't take any localization
- into account (they're US localized, if you will), they do the job.
-
- Plus, StringToExtended does just that...converts a string to an extended variable.
- extended's are part of Apple's SANE method of handling real numbers. SANE isn't
- all that happy with PowerMacs (the PowerPC chip) (that's part of the reason Apple
- is attempting to phase in fp.h in place of SANE.h). So, trying to use StringToExtended
- could cause you problems based on the chip and also if you generate 68881 instructions
- or not.
-
- I found a "smarter" way of dealing with StringToExtended in "develop" magazine's
- Q&A section. You can find these in HASUtilities.c as HsoiStringToExtended() and
- HsoiExtendedToString().
-
- If you'd like to use StringToExtended (or ExtendedToString), you'll want
- to check out Inside Macintosh: Text. it's in Chapter 5 i think. tells
- all about it.
-
- In a future release of HAS, i'll probably rewrite all this relevant stuff
- with StringToExtended to show how to use it all (but leave it just as
- commented out code so as not to cause compiler conflicts). Lemme know
- if you're interested in this sort of thing.
-
- whew! long explanation, but I hope I covered all the relevant stuff :)
-
- */
-
- double HsoiGetDoubleItem( DialogRef dialog, short item )
- {
- Handle itemHandle;
- Str255 itemText = {0}; // make sure it's a null terminated string
- double value;
-
- itemHandle = HsoiGetDialogItemHandle( dialog, item );
-
- GetDialogItemText( itemHandle, itemText );
-
- // ignore the length byte as we convert the string to a double
-
- sscanf( (char *)itemText + 1, "%lf", &value );
-
- return value;
- }
-
- // extract the numeric value from a dialog editable text item. returns legal = true if
- // result is in the given range of values (lo...hi). Decimals are stripped/ignored
-
- void HsoiGetDialogItemValue( DialogRef dlg, short item, double lo, double hi, Boolean *legal, double *result )
- {
- short i = 1;
-
- // assume it'll be legal
-
- *legal = true;
-
- // get the the numeric "equivalent" of the dialog's text
-
- *result = HsoiGetDoubleItem( dlg, item );
-
- // see if it's out of range
-
- if ( (*result < lo) || (*result > hi) )
- {
- *legal = false;
- if ( *result < lo )
- *result = lo;
- else if ( *result > hi )
- *result = hi;
- else // things go silly
- *result = lo; // arbitrary choice
- }
-
- return;
-
- }
-
- // handles the mouseDowns in the little up/down arrow controls
-
- void HsoiDoArrowUpDown( DialogRef dlg, /* the dialog we're doing this in */
- short itemHit, /* the total arrow rect user item # */
- short editTxtItem, /* the edit text box associated with this */
- short arrowRectItem, /* the little arrow user item rect */
- double increment, /* the amount to increment by (can be negative
- values for a decrement) */
- double loLimit, /* the lower limit of the control */
- double hiLimit, /* the upper limit of the control */
- Boolean isFraction, /* do we want real numbers or whole numbers? */
- double *variable ) /* pointer to the actual value */
- {
-
- GrafPtr savePort;
- long xx;
- Rect arrowRect; // rect of entire arrow picture
- Rect selectedRect; // area chosen (up or down area)
- Handle arrowHdl, arrowUpDnHdl;
- Handle editTxtHdl;
- Str255 s, s2;
- Point mLoc; // mouseDown location
- short wait;
-
- // get and set the ports
-
- GetPort( &savePort );
- SetGrafPortOfDialog( dlg );
-
- // get the selected/total arrow rects
-
- HsoiGetDialogItemRect( dlg, itemHit, &selectedRect );
- HsoiGetDialogItemRect( dlg, arrowRectItem, &arrowRect );
-
- // get plain/selected icons
-
- arrowHdl = GetIcon( rUpDownArrowIcon );
- if ( increment > 0 )
- arrowUpDnHdl = GetIcon( rUpArrowIcon );
- else
- arrowUpDnHdl = GetIcon( rDownArrowIcon );
-
- // draw the icon and select the related text box
-
- editTxtHdl = HsoiGetDialogItemHandle( dlg, editTxtItem );
- PlotIcon( &arrowRect, arrowUpDnHdl );
- SelectDialogItemText( dlg, editTxtItem, 0, 0 );
-
- // decrement wait in loop to speed up dragually
-
- wait = kDelayTime;
-
- // continue incrementing text value until mouseUp
-
- do
- {
- GetMouse( &mLoc );
-
- // continue while mouse stays in selectedRect
-
- if ( PtInRect( mLoc, &selectedRect ) )
- {
- PlotIcon( &arrowRect, arrowUpDnHdl );
-
- // increment, but keep variable in range
-
- *variable += increment;
- if ( *variable < loLimit )
- *variable = loLimit;
- else if ( *variable > hiLimit )
- *variable = hiLimit;
-
- // convert our amount into a string for easier manipulation
-
- if ( isFraction )
- // gives us a precision of 2 decimal places
- sprintf( (char *)s + 1, "%.2lf", *variable );
- else
- // gives us a precision of zero decimal places (i.e. no decimal,
- // nor nothing after it...a "whole" number)
- sprintf( (char *)s + 1, "%.lf", *variable );
-
- // just make sure the length byte [0] isn't the null character
- s[0] = 1; // arbitrary choice
- s[0] = strlen( (char *)s ) - 1; // minus 1 for that above arbitrary non-null stuff
-
- // and put this new value in the dialog, first making sure of
- // what's already in there
-
- GetDialogItemText( editTxtHdl, s2 );
- if ( !EqualString( s, s2, false, false ) )
- SetDialogItemText( editTxtHdl, s );
-
- // speed up incrementation
-
- if ( wait > 1 )
- wait -= 1;
-
- if ( StillDown() )
- Delay( wait, &xx );
-
- } // end: if (PtInRect(mLoc, &selectedRect))
-
- else // mouse out of rect. draw unselected picture
- PlotIcon( &arrowRect, arrowHdl );
-
- }
- while ( StillDown() );
-
- // hilite text and draw unselected picture
-
- SelectDialogItemText( dlg, editTxtItem, 0, MAXLONG );
- PlotIcon( &arrowRect, arrowHdl );
-
- SetPort( savePort );
-
- return;
-
- }
-
-
-